package com.minidb.cli;

import com.minidb.engine.*;
import com.minidb.sql_compiler.*;
import com.minidb.storage.BufferPool;
import com.minidb.storage.FileManager;
import com.minidb.utils.Constants;
import com.minidb.utils.Helpers;

import java.io.IOException;
import java.util.List;
import java.util.Scanner;

/**
 * Main 程序（已接入系统表 __catalog）
 * - 启动：通过 SystemCatalog + CatalogManager.loadFromSystemTable() 装载元数据
 * - 执行：保持原有流程；--debug 下打印 Token/AST/SEMANTIC/PLAN(JSON)
 */
public class Main {

    public static void main(String[] args) {
        boolean debug = false;
        for (String a : args) if ("--debug".equalsIgnoreCase(a)) debug = true;

        // === 初始化存储与缓存 ===
        FileManager fm = new FileManager("./data");
        BufferPool bp = new BufferPool(
                Constants.BUFFER_POOL_CAPACITY,
                fm,
                Constants.ReplacementPolicy.LRU
        );

        // === 系统表与目录管理 ===
        SystemCatalog syscat = new SystemCatalog(fm, bp);
        CatalogManager cm = new CatalogManager(fm, syscat);
        cm.loadFromSystemTable();   // ← 从 __catalog 装载所有表结构

        // === 编译器与执行引擎 ===
        Catalog catalog = new Catalog(cm);
        SyntaxParser parser = new SyntaxParser();
        SemanticAnalyzer semantic = new SemanticAnalyzer(catalog);
        StorageEngine storage = new StorageEngine(bp, fm, cm);
        Executor executor = new Executor(storage, cm);

        // 批处理（忽略 --debug）
        String[] files = java.util.Arrays.stream(args)
                .filter(a -> !a.equalsIgnoreCase("--debug"))
                .toArray(String[]::new);

        if (files.length > 0) {
            for (String path : files) {
                try {
                    List<String> sqls = Helpers.loadSQLFromFile(path);
                    for (String sql : sqls) runOnce(sql, parser, semantic, executor, debug);
                } catch (IOException e) {
                    System.err.println("读取SQL文件失败: " + path);
                }
            }
            bp.flushAll();
            return;
        }

        // 交互模式
        Scanner sc = new Scanner(System.in);
        System.out.println("MiniDB 已启动，输入 SQL（以分号结尾）或输入 quit 退出。");
        StringBuilder buf = new StringBuilder();
        while (true) {
            System.out.print("minidb> ");
            if (!sc.hasNextLine()) break;
            String line = sc.nextLine();
            if ("quit".equalsIgnoreCase(line.trim()) || "exit".equalsIgnoreCase(line.trim())) break;

            buf.append(line).append('\n');
            if (line.trim().endsWith(";")) {
                String sql = buf.toString().trim();
                if (sql.endsWith(";")) sql = sql.substring(0, sql.length() - 1);
                runOnce(sql, parser, semantic, executor, debug);
                buf.setLength(0);
            }
        }
        bp.flushAll();
    }

    /** 执行一条 SQL（含 debug 输出） */
    private static void runOnce(String sql,
                                SyntaxParser parser,
                                SemanticAnalyzer semantic,
                                Executor executor,
                                boolean debug) {
        try {
            if (debug) {
                var toks = new LexicalAnalyzer().tokenize(sql);
                System.out.println("TOKENS:");
                toks.forEach(t -> System.out.println("  " + t));
            }

            SQLStatement stmt = parser.parse(sql);
            if (debug) System.out.println("AST: " + stmt);

            semantic.analyze(stmt);
            if (debug) System.out.println("SEMANTIC: OK");

            // —— 调试用 JSON 计划树（仅展示，不参与执行） ——
            PlanNode planTree = buildPlanNodeForDebug(stmt);
            if (debug) {
                System.out.println("PLAN (JSON):");
                System.out.println(planTree.toJSON());
            }

            // —— 实际执行：转换为 ExecutionPlan 交给执行器 ——
            ExecutionPlan execPlan = buildExecPlan(stmt);
            String out = executor.executePlan(execPlan);
            System.out.println(out);

        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    // ---------------------------
    // 调试：构建执行计划树（仅打印）
    // ---------------------------
    private static PlanNode buildPlanNodeForDebug(SQLStatement s) {
        switch (s.type) {
            case SELECT -> {
                PlanNode scan = new PlanNode("SeqScan");
                scan.props.put("table", s.tableName);
                PlanNode top;
                if (s.condition != null) {
                    PlanNode filter = new PlanNode("Filter");
                    filter.props.put("condition", s.condition.toString());
                    filter.addChild(scan);
                    top = filter;
                } else {
                    top = scan;
                }
                PlanNode project = new PlanNode("Project");
                project.props.put("columns",
                        (s.columns == null || s.columns.isEmpty()) ? "*" : String.join(",", s.columns));
                project.addChild(top);
                return project;
            }
            case INSERT -> {
                PlanNode ins = new PlanNode("Insert");
                ins.props.put("table", s.tableName);
                ins.props.put("values", s.values == null ? "" : String.join(",", s.values));
                if (s.columns != null && !s.columns.isEmpty())
                    ins.props.put("columns", String.join(",", s.columns));
                return ins;
            }
            case CREATE_TABLE -> {
                PlanNode ct = new PlanNode("CreateTable");
                ct.props.put("table", s.tableName);
                ct.props.put("columns", String.join(",", s.columns));
                ct.props.put("types", String.join(",", s.columnTypes));
                return ct;
            }
            case DELETE -> {
                PlanNode scan = new PlanNode("SeqScan");
                scan.props.put("table", s.tableName);
                if (s.condition != null) {
                    PlanNode filter = new PlanNode("Filter");
                    filter.props.put("condition", s.condition.toString());
                    filter.addChild(scan);
                    PlanNode del = new PlanNode("Delete");
                    del.addChild(filter);
                    return del;
                } else {
                    PlanNode del = new PlanNode("Delete");
                    del.addChild(scan);
                    return del;
                }
            }
            default -> { return new PlanNode("Unknown"); }
        }
    }

    // ---------------------------
    // 执行：把 SQLStatement 转换为 ExecutionPlan
    // ---------------------------
    private static ExecutionPlan buildExecPlan(SQLStatement s) {
        ExecutionPlan p = new ExecutionPlan();
        p.type = s.type;
        p.tableName = s.tableName;
        p.columns = s.columns;
        p.columnTypes = s.columnTypes;
        p.values = s.values;
        p.condition = s.condition;
        return p;
    }
}
